package com.ssky.bean.validator.proxy;

import com.ssky.bean.validator.core.AbstractDepExpExeHandler;
import com.ssky.bean.validator.core.IDepExpExeHandler;
import com.ssky.bean.validator.core.VldConditionHanlder;
import com.ssky.bean.validator.core.IValidatorContext;
import com.ssky.bean.validator.core.VldConstants;
import com.ssky.bean.validator.core.rule.Rule;
import com.ssky.bean.validator.util.ExpUtil;
import javassist.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.StringTokenizer;

/**
 * @Author: ssky
 * @Date: 2021/07/30
 * @Description:
 */
public class DepExpExeHandlerCreator {

    private static final Logger L = LoggerFactory.getLogger(DepExpExeHandlerCreator.class);
    private static final String NLine = "\n";
    private static final String START_CLASS_NAME = "DepExpExe$_";

    private static final ClassPath classPath = new ClassClassPath(IDepExpExeHandler.class);
    private static final String PackageStr = DynProxyImplPackagePosition.class.getPackage().getName();
    private static final String packageVldContext = IValidatorContext.class.getPackage().getName();

    public DepExpExeHandlerCreator() {

    }

    public AbstractDepExpExeHandler create(Rule rule,VldConditionHanlder vldConditionHanlder) throws Exception {
        String ruleId = rule.getId();
        CtClass impCtClass = null;
        ClassPool pool = new ClassPool(true);
        pool.insertClassPath(classPath);
        CtClass ctSuperClass = pool.getCtClass(AbstractDepExpExeHandler.class.getName());
        pool.importPackage(packageVldContext);

        ruleId = ruleId.replace(".", "_").replace("-", "_");
        impCtClass = pool.makeClass(PackageStr + "." + START_CLASS_NAME + ruleId + VldConstants.Atomic_Long.getAndIncrement());
        impCtClass.setSuperclass(ctSuperClass);

        String methodStr = genMthodStr(rule);

        CtMethod method = null;
        try {
            method = CtNewMethod.make(methodStr, impCtClass);
            impCtClass.addMethod(method);
        } catch (CannotCompileException e) {
            L.error("impCtClass.addMethod(method) occur exception ,methodStr --->" + methodStr, e);
            throw e;
        }

        Class<AbstractDepExpExeHandler> clazz = (Class<AbstractDepExpExeHandler>) impCtClass.toClass(ValidatorClassLoader.getCustomCLoader(AbstractDepExpExeHandler.class));

        // todo   清除javassist缓存
        AbstractDepExpExeHandler handler = clazz.newInstance();
        handler.setConditionHanlder(vldConditionHanlder);

        return handler;
    }

    private static String genMthodStr(Rule rule) {
        String methodStr = "public boolean " + AbstractDepExpExeHandler.METHOD_NAME + " ( Object l, Object b, " + IValidatorContext.class.getSimpleName() + " " + "ctx" + ")" + NLine;

        StringBuilder body = new StringBuilder();
        body.append("{").append("return ").append(toExpJavaStr(rule.getAllDepExp())).append(" ; }").append(NLine);
        methodStr = methodStr + body.toString();
        if (L.isDebugEnabled()) {
            L.debug(methodStr);
        }
        return methodStr;
    }

    private static String toExpJavaStr(String allDepExp) {
        StringBuilder javaExpSb = new StringBuilder();
        StringTokenizer token = new StringTokenizer(allDepExp, ExpUtil.OPERATOR_LOGIC, true);
        while (token.hasMoreTokens()) {
            String str = token.nextToken().trim();
            if (ExpUtil.isElement(str)) {
                javaExpSb.append(AbstractDepExpExeHandler.Condition_Cache_Field_Name + "." + AbstractDepExpExeHandler.METHOD_NAME
                        + "(\"" + str + "\", l, b, ctx )");
                continue;
            }
            javaExpSb.append(ExpUtil.toJavaOperate(str));
        }
        return javaExpSb.toString();
    }

}
